
local insert = table.insert;
local format = string.format;
local log_debug = function(f,...)
    local s = format(f,...);
    print(s);
end

--关闭debug
log_debug = function() end

local function init_usb()
    local lusb = require "lusb";
    package.cpath = package.cpath .. [[;E:\msys2\mingw32\bin\..\lib\lua\5.4\?.dll;E:\msys2\mingw32\bin\..\lib\lua\5.4\..\lib\lua\5.4\\?.dll;E:\msys2\mingw32\bin\..\lib\lua\5.4\loadall.dll;.\?.dll]];
    package.path = package.path .. [[;E:\msys2\mingw32\bin\..\share\lua\5.4\?.lua;E:\msys2\mingw32\bin\..\share\lua\5.4\?\init.lua;E:\msys2\mingw32\bin\..\lib\lua\5.4\?.lua;E:\msys2\mingw32\bin\..\lib\lua\5.4\?\init.lua;E:\msys2\mingw32\bin\..\share\lua\5.4\\?.lua;E:\msys2\mingw32\bin\..\share\lua\5.4\\?\init.lua;.\?.lua;.\?\init.lua]];
    local format = string.format;
    local desc_key = {
    --[[uint8_t ]] 1,0, 'bLength',
    --[[uint8_t ]] 1,1, 'bDescriptorType',
    --[[uint16_t]] 2,2, 'bcdUSB',
    --[[uint8_t ]] 1,4, 'bDeviceClass',
    --[[uint8_t ]] 1,5, 'bDeviceSubClass',
    --[[uint8_t ]] 1,6, 'bDeviceProtocol',
    --[[uint8_t ]] 1,7, 'bMaxPacketSize0',
    --[[uint16_t]] 2,8, 'idVendor',
    --[[uint16_t]] 2,10,'idProduct',
    --[[uint16_t]] 2,12,'bcdDevice',
    --[[uint8_t ]] 1,14,'iManufacturer',
    --[[uint8_t ]] 1,15,'iProduct',
    --[[uint8_t ]] 1,16,'iSerialNumber',
    --[[uint8_t ]] 1,17,'bNumConfigurations',}

    for k=1,#desc_key,3 do
        local sz  = desc_key[k];
        local key = desc_key[k+2];
        local off = desc_key[k+1];
        desc_key[key] = {off,sz}
    end

    print();
    local usb_list = {lusb.lusb_list()};
    print(#usb_list);
    for k=1,#usb_list,2 do
        print(string.format("%04x,%04x",usb_list[k],usb_list[k+1]));
    end
    --os.exit();

    --daplink
    local vid = 0x0d28;
    local pid = 0x4011;

    --wch link
    local vid = 0x1a86;
    local pid = 0x8011;

    --gw2ux
    local vid = 0x33aa;
    local pid = 0x0120;

    local usb_dev,err = lusb.lusb_open(vid,pid);
    local err_str = lusb.lusb_error_name(err or 0);
    --print(usb_dev,err_str);

    local function usb_err(err,err2)
        if (err==0) or (not err) then return; end;
        local err_str = lusb.lusb_error_name(err);
        print('error!',err_str);
        return true;
    end

    if (not usb_dev) or usb_err(err) then
        io.stderr:write('error usb!\n');
        os.exit(-1);
    end

    print('init done!',usb_dev);
    --print(usb_dev);
    --设置usb接口
    local config,err = lusb.lusb_get_configuration(usb_dev);
    print('get config!',config,err);
    usb_err(lusb.lusb_set_configuration(usb_dev,config));

    local desc,err = lusb.lusb_get_device_desc(usb_dev);
    usb_err(err);
    print('get device desc',desc,err);

    local desc = {ptr=desc};

    desc = setmetatable(desc, {
        __index = function(self,key)
            --访问目标字段
            local att = desc_key[key] or {0,0};
            local offset = att[1];
            local sz = att[2];
            return lusb.mem_value(self.ptr,offset,sz);
        end,
    })

    print(desc.bLength);
    print(format('vid:%04x,pid:%04x',desc.idVendor,desc.idProduct));
    print('num config:',desc.bNumConfigurations);

    if true then
        --输出信息
        local ret = {lusb.lusb_get_config_descriptor(usb_dev,0)};
        local err = ret[1];
        local bConfigurationValue = ret[2];

        print('config0',#ret,ret[1]);
        print('===================',bConfigurationValue);
        for k,v in ipairs(ret)do
            if(v=='|')then
                print('---------------');
            else
                print(v);
            end
        end
    end

    print('set_config!');
    usb_err(lusb.lusb_set_configuration(usb_dev,1));

    print('start!')
    usb_err( lusb.lusb_claim_interface(usb_dev,0));


    local p = lusb.mem_new(1024);

    --JTAG模式,0,1,2 为输出.4为输入
    local cmd = '\x20\x07\x00';       --TDI输出数据

    local send,err =
    lusb.lusb_bulk_transfer(usb_dev,
        0x02,
        cmd,
        #cmd,   --发送长度
        1000
    );

    usb_tran_func = function(usb_buf,read_bytes)
        if(type(usb_buf)=='table')then
            --需要转换一下
            local t = {};
            for k,v in ipairs(usb_buf)do
                insert(t,string.char(v));
            end
            usb_buf = table.concat(t);
        end

        if(usb_buf)then
            local send,err = lusb.lusb_bulk_transfer(usb_dev,0x02,usb_buf,#usb_buf,1000);
        end

        if(read_bytes and read_bytes>0)then
            --读取usb数据
            local r_len = 0;
            local r_data = {};

            while(r_len < read_bytes )do
                local recv_len,recv,err = lusb.lusb_bulk_transfer(usb_dev,0x81,nil,read_bytes,1000);
                r_len = r_len + recv_len;
                log_debug('usb recv len:%d',r_len);
                if(r_len==0)then
                    os.exit();
                end
                if(recv_len>0)then
                    insert(r_data,recv);
                end
            end

            return table.concat(r_data);
        end

    end

end --init_usb

--初始化usb
init_usb();
require('gw2ux_jtag');

--设置usb传输函数
usb_set_tran_func(usb_tran_func);

local host = "127.0.0.1";
local port = '3456'

local socket = require("socket.core")
local tcp = socket.tcp()
local tcpbind = tcp:bind(host,port)
local e = tcp:listen(50)
local client = nil;


local bool_int = {
    [false] = 0,
    [true] = 1,
};

print('remote ip:',host,port);

local usb_buf = {};

local function usb_write_byte(byt)
    local d = byt & 0xff;

    --测试输出
    d = format('%02X',d);

    insert(usb_buf,d);
end

local function usb_write_cmd_and_len(cmd,len)
    usb_write_byte(cmd);
    usb_write_byte(len);
end

local function usb_write_tms_byte(tms,tdi)
    usb_write_byte((tms&0x7f)|(tdi<<7));
end

local function usb_flush()
    local s = table.concat(usb_buf,',');
    log_debug('------------usb send:%s',s);
    --初始化
    usb_buf = {};
end

while true do
    client = tcp:accept()
    client:settimeout(0);

    remote_bitbang_func = function(d)
        client:send(d);
    end

    print('link!');
    while(true)do
        client:settimeout(0);
        if client ~= nil then
            local rbuf, err,part = client:receive(1024);
            local data = nil;
            if(err=='timeout')then
                data = part;
            elseif(err==nil)then
                data = rbuf;
            end
            if(data and #data>0)then
                log_debug('%s',data);
                --转换数据
                --------------------------------------------------------------------------------------------------------
                --lua实现
                --[[
                    bit0: tdi
                    bit1: tms
                    bit2: tck
                ]]

                --替换一些其他命令
                data = data:gsub('[bBrQ]','');

                remote_bitbang(data);
                --------------------------------------------------------------------------------------------------------

            else
                --print(err);
            end

        end
    end
end

tcp:close()

